home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’89 / gadlife / source (ugly) / data.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-14  |  15.7 KB  |  510 lines  |  [TEXT/KAHL]

  1. /*******************************************************
  2. *                                                                *
  3. *    data.c contains most of the routines for dealing with the actual structure of the    *
  4. *    dataState records.  Although currently these structures may be manipulated    *
  5. *    by other routines, this may change.                                    *
  6. *                                                                *
  7. *******************************************************/
  8.  
  9. #include "main.h"
  10.  
  11. extern Pattern        dragPat,
  12.                 *getAnts();
  13. extern long        timer();
  14. extern int            isBackground;
  15. extern char        *NewPtrClear();
  16.  
  17. dataHandle        currentData = NULL;
  18. long                defaultCycleLength = 36;        /* should be read from a string at startup */
  19.  
  20. /*******************************************************
  21. *                                                                *
  22. *    LinkedInsert and LinkedDelete maintain a doubly linked list of dataStates.  This    *
  23. *    list is refered into by the refCons of the parent windows of the dataStates and    *
  24. *    by the global currentData, which points to the one currently being considered    *
  25. *    for stepping or copying.                                            *
  26. *                                                                *
  27. *******************************************************/
  28.  
  29. dataHandle linkedInsert( head, new )
  30.     dataHandle    head, new;
  31.     {
  32.     if( head )
  33.         {
  34.         (**new).next = head;
  35.         (**new).prev = (**head).prev;
  36.         (**head).prev = new;
  37.         (**(**new).prev).next = new;
  38.         }
  39.     else    (**new).next = (**new).prev = new;
  40.     return( new );
  41.     }
  42.  
  43. dataHandle linkedDelete( old )
  44.     dataHandle    old;
  45.     {
  46.     if( (**old).next != old )
  47.         {
  48.         (**(**old).next).prev = (**old).prev;
  49.         (**(**old).prev).next = (**old).next;
  50.         return( (**old).next );
  51.         }
  52.     return( NULL );
  53.     }
  54.  
  55. /*******************************************************
  56. *                                                                *
  57. *    DisposeData is called when a window is closed to dispose of all of the storage    *
  58. *    associated with a dataState.  This can be quite a lot, with up to five bitmaps    *
  59. *    and several regions.                                                *
  60. *                                                                *
  61. *******************************************************/
  62.  
  63. disposeData( theDataHand )
  64.     dataHandle    theDataHand;
  65.     {
  66.     dataPtr        theData;
  67.     int            i;
  68.  
  69.     HLock( theDataHand );
  70.     theData = *theDataHand;
  71.     if( theData->state ) --isBackground;
  72.     for( i = 0; i < theData->planes; ++i )
  73.         DisposPtr( theData->bases[ i ] );
  74.     DisposPtr( theData->allBits.baseAddr );
  75.     DisposeRgn( theData->selRgn );
  76.     if( theData->isSelect )
  77.         DisposPtr( theData->selBits.baseAddr );
  78.     if( theData->cycleFlags != cycleNone && theData->cycleBase )
  79.         DisposHandle( theData->cycleBase );
  80.     currentData = linkedDelete( theDataHand );
  81.     DisposHandle( theDataHand );
  82.     }
  83.  
  84. /*******************************************************
  85. *                                                                *
  86. *    NewData assumes that the window has already been set as the current port    *
  87. *    and all that, and creates a new dataState record, pointing the refCon of the    *
  88. *    parent window at it.  All fields are initialized - on the first updateEvent the    *
  89. *    (zero) contents will be rendered and displayed.                            *
  90. *                                                                *
  91. *******************************************************/
  92.  
  93. newData( theWindow, theFont, flags )
  94.     WindowPtr    theWindow;
  95.     dataFontPtr    theFont;
  96.     int            flags;
  97. {
  98.     dataHandle    theDataHand;
  99.     dataPtr        theData;
  100.     int            i, errno;
  101.  
  102.     theDataHand = (dataHandle)NewHandle(( long )sizeof( dataState ));
  103.     if( errno = MemError() ) hardPanic( errno, memPanic );
  104.     HLock( theDataHand );
  105.     theData = *theDataHand;
  106.     theData->parent = theWindow;
  107.     SetWRefCon( theWindow, theDataHand );
  108.     currentData = linkedInsert( currentData, theDataHand );
  109.     theData->theFont = *theFont;
  110.     theData->state = dataStopped;
  111.     theData->planes = 2;
  112.     theData->flags = flags;
  113.     theData->changed = timer();
  114.     theData->generation = 0;
  115.     theData->undoGeneration = 0;
  116.     theData->undoFlags = undoNone;
  117.     theData->partDone = 0;
  118.     theData->isSelect = 0;
  119.     theData->selActive = 0;
  120.     theData->lastGenWidth = 0;            /* was missing! - big bug… */
  121.     theData->cycleLength = defaultCycleLength;
  122.     theData->cycleFlags = cycleNone;
  123.     theData->selRgn = NewRgn();
  124.     if( errno = MemError() ) hardPanic( errno, memPanic );
  125.  
  126.     setDataBounds( theData );
  127.     for( i = 0; i < theData->planes; ++i ) {
  128.         theData->bases[ i ] = NewPtrClear( theData->planeSize );
  129.         if( errno = MemError() ) hardPanic( errno, memPanic );
  130.     }
  131.     theData->offBits.baseAddr = theData->bases[0];
  132.     
  133.     HUnlock( theDataHand );
  134. }
  135.  
  136. /*******************************************************
  137. *                                                                *
  138. *    StopData is called both by the 'stop' menu command and by drawing routines    *
  139. *    which require a non-changing bitmap to work with.  The force flag forces any    *
  140. *    pending drawing to be completed.  The previous state is returned, so that the    *
  141. *    data may be restarted.                                            *
  142. *                                                                *
  143. *******************************************************/
  144.  
  145. stopData( theData, force )
  146.     dataPtr        theData;
  147.     int            force;
  148. {
  149.     int            oldState;
  150.  
  151.     oldState = theData->state;
  152.     if( oldState != dataStopped )
  153.         if( theData->partDone < -1 && force == dontForceStop )
  154.             theData->state = dataStepping;
  155.         else {
  156.             if( theData->partDone < -1 )
  157.                 finishCopy( theData );
  158.             theData->state = dataStopped;
  159.             if( oldState != dataStopped )
  160.                 --isBackground;
  161.             if( force == forceStop ) theData->partDone = 0;
  162.         }
  163.     return( oldState );
  164. }
  165.  
  166. /*******************************************************
  167. *                                                                *
  168. *    restartData is used to restore the previous state of data that has been stopped    *
  169. *    by a drawing routine, using stopData.                                *
  170. *                                                                *
  171. *******************************************************/
  172.  
  173. restartData( theData, oldState )
  174.     dataPtr        theData;
  175.     int            oldState;
  176. {
  177.     if( oldState ) ++isBackground;
  178.     theData->state = oldState;
  179. }
  180.  
  181. madeChange( theData )
  182.     dataPtr    theData;
  183. {
  184.     theData->changed = timer();
  185.     theData->undoGeneration = theData->generation;
  186.     theData->undoFlags |= undoData;
  187.     theData->allBitsState |= bitsBadData + bitsBadGen;
  188. }
  189.  
  190. swapPlane( theData )
  191.     dataPtr    theData;
  192. {
  193.     theData->offBits.baseAddr = theData->bases[1];
  194.     theData->bases[1] = theData->bases[0];
  195.     theData->bases[0] = theData->offBits.baseAddr;
  196.     theData->undoGeneration = theData->generation;
  197. }
  198.  
  199. /*******************************************************
  200. *                                                                *
  201. *    reshapeData re-allocates memory for the data from scratch, and copies the    *
  202. *    previous state into the new space.  The bounds are taken from the window        *
  203. *    bounds of the data's parent, using setDataBounds.  If cycle-detection is on, the    *
  204. *    new data bits are copied into a new cycle-detection bitmap, and the counter    *
  205. *    is started over.                                                    *
  206. *                                                                *
  207. *******************************************************/
  208.  
  209. reshapeData( theDataHand )
  210.     dataHandle        theDataHand;
  211. {
  212.     BitMap        oldBits, *newBits;
  213.     Rect            bounds;
  214.     dataPtr        theData;
  215.     long            oldSize;
  216.     int            i, errno;
  217.     
  218.     HLock( theDataHand );
  219.     theData = *theDataHand;
  220.     oldBits = theData->offBits;
  221.     oldSize = theData->planeSize;
  222.     DisposPtr( theData->allBits.baseAddr );
  223.     setDataBounds( theData );
  224.     newBits = &( theData->offBits );
  225.     SectRect( &( oldBits.bounds ), &( newBits->bounds ), &bounds );
  226.     SectRect( &( theData->parent->portRect ), &bounds, &bounds );
  227.     for( i = 0; i < theData->planes; ++i ) {
  228.         oldBits.baseAddr = theData->bases[ i ];
  229.         newBits->baseAddr = theData->bases[ i ] = NewPtrClear( theData->planeSize );
  230.         if( errno = MemError() ) hardPanic( errno, memPanic );
  231.         CopyBig( &oldBits, newBits, &bounds, &bounds, srcCopy, NULL );
  232.         DisposPtr( oldBits.baseAddr );
  233.     }
  234.     theData->partDone = 0;
  235.     newBits->baseAddr = theData->bases[ 0 ];
  236.     if( theData->cycleFlags != cycleNone ) {
  237.         if( theData->cycleBase )
  238.             DisposHandle( theData->cycleBase );
  239.         /* error in this allocation will cause no problems - just postpone detection */
  240.         PtrToHand( theData->bases[ 0 ], &theData->cycleBase, theData->planeSize );
  241.         if( theData->cycleBase ) HPurge( theData->cycleBase );
  242.         theData->cycleGeneration = theData->generation;
  243.         theData->cycleFitLength = theData->cycleLength;
  244.     }
  245.     HUnlock( theDataHand );
  246. }
  247.  
  248. /*******************************************************
  249. *                                                                *
  250. *    These currently simply re-allocate the memory used by the data.  They could    *
  251. *    be updated to test for the case that the same amount of memory is needed as    *
  252. *    before, or this change could be made to the reshapeData routine, perhaps more    *
  253. *    productively.                                                    *
  254. *                                                                *
  255. *******************************************************/
  256.  
  257. shiftData( theDataHand )
  258.     dataHandle        theDataHand;
  259. {
  260.     reshapeData( theDataHand );
  261. }
  262.  
  263. sizeData( theDataHand )
  264.     dataHandle        theDataHand;
  265. {
  266.     reshapeData( theDataHand );
  267. }
  268.  
  269. /*******************************************************
  270. *                                                                *
  271. *    setDataBounds resets the bounds, rowBytes, and planeSize from scratch.        *
  272. *    There used to be a special case for new, shift, and size, but this puts it all in    *
  273. *    one place, so it can be updated easily.                                *
  274. *                                                                *
  275. *******************************************************/
  276.  
  277. setDataBounds( theData )
  278.     dataPtr        theData;
  279. {
  280.     WindowPtr    theWindow = theData->parent;
  281.     BitMap        *theBits;
  282.     long            planeSize;
  283.     int            h, w, rowBytes, ldiff, errno;
  284.     
  285.     theBits = &( theData->offBits );
  286.     theData->dataRect = theWindow->portRect;
  287.     if( theData->flags & dataStatLine )
  288.         theData->dataRect.top += theData->theFont.topSpace;
  289.     theBits->bounds = theData->dataRect;
  290.     ldiff = ( theData->dataRect.left - theWindow->portBits.bounds.left ) & 15;
  291.     theBits->bounds.left -= ldiff ? ldiff : 16;
  292.     w = theBits->bounds.right - theBits->bounds.left;
  293.     rowBytes = (( w + 32 ) >> 3 ) & longMask;
  294.     theBits->rowBytes = rowBytes;
  295.     h = theBits->bounds.bottom - theBits->bounds.top;
  296.     theData->planeSize = (long)h * rowBytes + 16;
  297.     
  298.     theData->allBits.bounds = theBits->bounds;
  299.     theData->allBits.bounds.top = theWindow->portRect.top;
  300.     theData->allBits.rowBytes = rowBytes;
  301.     h = theData->allBits.bounds.bottom - theData->allBits.bounds.top;
  302.     theData->allBits.baseAddr = NewPtrClear(( long )h * rowBytes );
  303.     if( errno = MemError() ) hardPanic( errno, memPanic );
  304.     theData->allBitsState = bitsBadData | bitsBadFrame | bitsBadSel | bitsBadGen;
  305. }
  306.  
  307. /*******************************************************
  308. *                                                                *
  309. *    CopyDisplay draws the gray onto the bitmap to be copied, clips to the current    *
  310. *    menuRgn, and copies the bounds rectangle from the source bitmap to thePort.    *
  311. *                                                                *
  312. *******************************************************/
  313.  
  314. copyDisplay( source, bounds, mask, gray )
  315.     BitMap        *source;
  316.     Rect            *bounds;
  317.     RgnHandle        mask, gray;
  318. {
  319.     RgnHandle        saveClip;
  320.     
  321.     saveClip = NewRgn();
  322.     doMenuClip( saveClip );
  323.     drawGray( source, bounds, gray );
  324.     CopyBig( source, &( thePort->portBits ), bounds, bounds, srcCopy, mask );
  325.     drawGray( source, bounds, gray );
  326.     SetClip( saveClip );
  327.     DisposeRgn( saveClip );
  328. }
  329.  
  330. /*******************************************************
  331. *                                                                *
  332. *                                                                *
  333. *******************************************************/
  334.  
  335. displayData( theData, toDraw, gray )
  336.     dataPtr        theData;
  337.     int            toDraw;
  338.     RgnHandle        gray;
  339. {
  340.     Rect            bounds;
  341.     RgnHandle        maskRgn;
  342.     
  343.     if( EmptyRgn((( WindowPeek )( theData->parent ))->updateRgn )) {
  344.         if( theData->generation != theData->lastGeneration && ( toDraw & bitsBadGen ) && ( theData->flags & dataStatLine )) {
  345.             updateGen( theData, &bounds );
  346.             copyDisplay( &( theData->allBits ), &bounds, NULL, gray );
  347.         }
  348.         if( toDraw & bitsBadData ) {
  349.             maskRgn = NewRgn();
  350.             RectRgn( maskRgn, &( theData->dataRect ));
  351.             if( theData->isSelect )
  352.                 DiffRgn( maskRgn, theData->selRgn, maskRgn );
  353.             copyDisplay( &( theData->offBits ), &( theData->dataRect ), maskRgn, gray );
  354.             DisposeRgn( maskRgn );
  355.         }
  356.         if( toDraw & bitsBadSel && theData->isSelect ) {
  357.             maskRgn = NewRgn();
  358.             CopyRgn( theData->selRgn, maskRgn );
  359.             if( theData->selActive ) InsetRgn( maskRgn, 1, 1 );
  360.             copyDisplay( &( theData->selBits ), &( theData->selBits.bounds ), maskRgn, gray );
  361.             DisposeRgn( maskRgn );
  362.         }
  363.         theData->allBitsState |= toDraw;
  364.     } else {
  365.         fixAllBits( theData );
  366.         BeginUpdate( theData->parent );
  367.         EndUpdate( theData->parent );
  368.         copyDisplay( &( theData->allBits ), &( theData->parent->portRect ), NULL, gray );
  369.     }
  370. }
  371.  
  372. updateGen( theData, bounds )
  373.     dataPtr        theData;
  374.     Rect            *bounds;
  375.     {
  376.     char            theString[ pasStrLen ], *numStart;
  377.     BitMap        saveBits;
  378.     RgnHandle        saveVis;
  379.     WindowPtr    theWindow;
  380.     int            nextWidth, modWidth, genStart;
  381.     
  382.     saveVis = NewRgn();
  383.     theWindow = theData->parent;
  384.     CopyRgn( theWindow->visRgn, saveVis );
  385.     setBigRgn( theWindow->visRgn );
  386.     saveBits = thePort->portBits;
  387.     SetPortBits( &( theData->allBits ));
  388.  
  389.     displayNumPas( theData->generation, theString + 255, &numStart );
  390.     nextWidth = StringWidth( numStart );
  391.     modWidth = max( nextWidth, theData->lastGenWidth );
  392.     theData->lastGenWidth = nextWidth;
  393.     theData->lastGeneration = theData->generation;
  394.     
  395.     genStart = theData->theFont.genStart;
  396.     SetRect( bounds, genStart, 0, genStart + modWidth, theData->theFont.topSpace - 1 );
  397.     EraseRect( bounds );
  398.     MoveTo( genStart, theData->theFont.topStart );
  399.     DrawString( numStart );
  400.     theData->allBitsState &= -1 - bitsBadGen;
  401.     
  402.     SetPortBits( &saveBits );
  403.     CopyRgn( saveVis, theWindow->visRgn );
  404.     DisposeRgn( saveVis );
  405.     }
  406.  
  407. fixAllBits( theData )
  408.     dataPtr        theData;
  409.     {
  410.     char            theString[ pasStrLen ], *numStart;
  411.     PenState        savePen;
  412.     BitMap        saveBits;
  413.     Rect            *bounds;
  414.     RgnHandle        saveVis, tempRgn;
  415.     WindowPtr    theWindow;
  416.     int            state;
  417.     
  418.     saveVis = NewRgn();
  419.     theWindow = theData->parent;
  420.     CopyRgn( theWindow->visRgn, saveVis );
  421.     setBigRgn( theWindow->visRgn );
  422.     saveBits = thePort->portBits;
  423.     SetPortBits( &( theData->allBits ));
  424.     GetPenState( &savePen );
  425.     
  426.     tempRgn = NewRgn();
  427.     RectRgn( tempRgn, &( theData->dataRect ));
  428.     state = theData->allBitsState;
  429.     if( theData->isSelect )
  430.         {
  431.         bounds = &( theData->selBits.bounds );
  432.         if(( state & bitsBadSel ) || (( state & bitsBadAnts ) && ( theData->selActive == 0 )))
  433.             CopyBig( &( theData->selBits ), &( theData->allBits ), bounds, bounds, srcCopy, theData->selRgn );
  434.         if( theData->selActive && ( state & ( bitsBadAnts + bitsBadSel )))
  435.             {
  436.             PenMode( patCopy );
  437.             PenPat( getAnts( theData->antSkew ));
  438.             FrameRgn( theData->selRgn );
  439.             }
  440.         if( state & bitsBadData )
  441.             DiffRgn( tempRgn, theData->selRgn, tempRgn );
  442.         }
  443.     if( state & bitsBadData )
  444.         {
  445.         bounds = &( theData->dataRect );
  446.         CopyBig( &( theData->offBits ), &( theData->allBits ), bounds, bounds, srcCopy, tempRgn );
  447.         }
  448.     if(( state & bitsBadFrame ) && ( theData->flags & dataStatLine ))
  449.         {
  450.         PenPat( black );
  451.         PenMode( patOr );
  452.         MoveTo( 0, theData->theFont.topSpace - 1 );
  453.         Line( thePort->portRect.right, 0 );
  454.         MoveTo( leftMargin, theData->theFont.topStart );
  455.         GetIndString( theString, statStrings, genStr );
  456.         DrawString( theString );
  457.         }
  458.     if(( state & bitsBadGen ) && ( theData->flags & dataStatLine ))
  459.         {
  460.         displayNumPas( theData->generation, theString + pasStrLen - 1, &numStart );
  461.         MoveTo( theData->theFont.genStart, theData->theFont.topStart );
  462.         DrawString( numStart );
  463.         }
  464.     theData->allBitsState = 0;
  465.     
  466.     DisposeRgn( tempRgn );
  467.     SetPenState( &savePen );
  468.     SetPortBits( &saveBits );
  469.     CopyRgn( saveVis, theWindow->visRgn );
  470.     DisposeRgn( saveVis );
  471.     }
  472.  
  473. /*******************************************************
  474. *                                                                *
  475. *    drawGray draws a gray region onto the given bitmap, USING THEPORT.  That    *
  476. *    is, you have to arrange for the current port to be set up, but don't need to        *
  477. *    worry about changing portBits.  When it returns, all is as it was before.  The    *
  478. *    gray is Xor-ed on, so a second call after using the bitmap will return to the    *
  479. *    original state.  The origin is adjusted so that the dragPat is drawn with the    *
  480. *    same shift as it would be in the original bitmap, and then adjusted back.        *
  481. *                                                                *
  482. *******************************************************/
  483.  
  484. drawGray( whichBits, bounds, theGray )
  485.     BitMap        *whichBits;
  486.     Rect            *bounds;
  487.     RgnHandle        theGray;
  488.     {
  489.     GrafPort        tempPort;
  490.     GrafPtr        savePort;
  491.     Point            off;
  492.  
  493.     if( theGray )
  494.         {
  495.         off = topLeft( thePort->portBits.bounds );
  496.         GetPort( &savePort );
  497.         OpenPort( &tempPort );
  498.         SetPortBits( whichBits );
  499.         thePort->portRect = savePort->portRect;
  500.         PenMode( notPatXor );
  501.         PenPat( dragPat );
  502.         SetOrigin( -off.h, -off.v );
  503.         ClipRect( bounds );
  504.         OffsetRgn( thePort->clipRgn, -off.h, -off.v );
  505.         CopyRgn( thePort->clipRgn, thePort->visRgn );
  506.         PaintRgn( theGray );
  507.         SetPort( savePort );
  508.         ClosePort( &tempPort );
  509.         }
  510.     }